package com.ruoyi.web.controller.biz;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.common.utils.CollectionUtils;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.IdCardUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.domain.dto.BsKbConsumeTopDto;
import com.ruoyi.system.domain.dto.BsStatisticFlowAreaDto;
import com.ruoyi.system.domain.dto.BsStatisticFlowTopDto;
import com.ruoyi.system.domain.dto.BsStatisticOperateTopDto;
import com.ruoyi.system.mapper.BsQiyeBusinessDataMapper;
import com.ruoyi.system.mapper.BsQiyeMapper;
import com.ruoyi.system.service.BsJingquService;
import com.ruoyi.system.service.BsOrderDetailsService;
import com.ruoyi.system.service.BsOrderInfoService;
import com.ruoyi.system.service.BsUserContractService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Description TODO
 * @ClassName BsStatisticController
 * @Author kenn
 * @Version 1.0.0
 * @Date 2023年11月16日 13:50:00
 */
@RestController
@RequestMapping("/bs/statistic")
@Api(tags = "统计图表")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class BsStatisticController {

    private final BsJingquService jingquService;
    private final BsQiyeMapper qiyeMapper;
    private final BsOrderInfoService orderInfoService;
    private final BsOrderDetailsService orderDetailsService;
    private final BsQiyeBusinessDataMapper qiyeBusinessDataMapper;
    private final BsUserContractService contractService;

    @GetMapping("/kb/today/flow")
    @ApiOperation("客流分析看板-今日人流数量")
    public Result<Map<String, Object>> kbTodayFlow() {
        LocalDate localDate = LocalDate.now();
        LocalDate yesterdayDate = localDate.minusDays(1);
        Map<String, Object> todayMap = flowInfo(localDate, localDate);
        Map<String, Object> yesterdayMap = flowInfo(yesterdayDate, yesterdayDate);
        int todayTotal = (int) todayMap.get("total");
        int yesterdayTotal = (int) yesterdayMap.get("total");
        BigDecimal qoq = yesterdayTotal == 0 ? BigDecimal.valueOf(todayTotal).divide(new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_UP) : new BigDecimal((todayTotal - yesterdayTotal) + "").multiply(new BigDecimal("100")).divide(BigDecimal.valueOf(yesterdayTotal), 2, BigDecimal.ROUND_HALF_UP);

        Map<String, Object> resultMap = new HashMap<>(3);
        resultMap.put("today", todayTotal);
        resultMap.put("yesterday", yesterdayTotal);
        resultMap.put("qoq", qoq);
        return Result.success(resultMap);
    }

    @GetMapping("/kb/sex/info")
    @ApiOperation("客流分析看板-游客画像")
    public Result<Map<String, Object>> kbSexInfo(String startDate, String endDate) {
        LocalDate start = StringUtils.isEmpty(startDate) ? LocalDate.parse("2022-01-01") : LocalDate.parse(startDate);
        LocalDate end = StringUtils.isEmpty(endDate) ? LocalDate.now() : LocalDate.parse(endDate);

        // 判断时间范围正确性
        DateUtils.judgeDate(start, end);

        Map<String, Object> flowInfoMap = flowInfo(start, end);
        int male = (int) flowInfoMap.get("male");
        int female = (int) flowInfoMap.get("female");

        List<Integer> countList = Arrays.asList(male, female);
        List<Double> reateList = CollectionUtils.fullRatePercent(countList.stream().map(BigDecimal::valueOf).collect(Collectors.toList()), 1);
        Map<String, Object> resultMap = new HashMap<>(3);
        resultMap.put("sex", Arrays.asList("男性", "女性"));
        resultMap.put("count", countList);
        resultMap.put("rate", reateList);
        return Result.success(resultMap);
    }

    @GetMapping("/kb/today/consume")
    @ApiOperation("客流分析看板-游客消费")
    public Result<Map<String, Object>> kbTodayConsume() {
        LocalDate localDate = LocalDate.now();
        LocalDate yesterdayDate = localDate.minusDays(1);
        Map<String, Object> todayMap = consumeInfo(localDate, localDate);
        Map<String, Object> yesterdayMap = consumeInfo(yesterdayDate, yesterdayDate);
        BigDecimal todayTotal = (BigDecimal) todayMap.get("totalPrice");
        BigDecimal yesterdayTotal = (BigDecimal) yesterdayMap.get("totalPrice");
        BigDecimal subtract = todayTotal.subtract(yesterdayTotal);
        BigDecimal qoq = yesterdayTotal.doubleValue() == 0 ? todayTotal.divide(new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_UP) : subtract.multiply(new BigDecimal("100")).divide(yesterdayTotal, 2, BigDecimal.ROUND_HALF_UP);

        Map<String, Object> resultMap = new HashMap<>(3);
        resultMap.put("today", todayTotal);
        resultMap.put("yesterday", yesterdayTotal);
        resultMap.put("qoq", qoq);
        return Result.success(resultMap);
    }

    @GetMapping("/kb/jingqu/flow")
    @ApiOperation("客流分析看板-热门景区排名")
    public Result<List<BsStatisticFlowTopDto>> kbJingquFlow(String startDate, String endDate) {
        LocalDate start = StringUtils.isEmpty(startDate) ? LocalDate.parse("2022-01-01") : LocalDate.parse(startDate);
        LocalDate end = StringUtils.isEmpty(endDate) ? LocalDate.now() : LocalDate.parse(endDate);
        // 判断时间范围正确性
        DateUtils.judgeDate(start, end);
        List<BsStatisticFlowTopDto> resultList = jingquFlowInfo(start, end);
        if (CollUtil.isNotEmpty(resultList)) {
            resultList = resultList.stream().sorted(Comparator.comparing(BsStatisticFlowTopDto::getUserCount).reversed())
                    .collect(Collectors.toList());
        }
        return Result.success(resultList);
    }

    @GetMapping("/kb/consume/type")
    @ApiOperation("客流分析看板-游客消费类型分析")
    public Result<Map<String, Object>> kbConsumeType(String startDate, String endDate) {
        LocalDate start = StringUtils.isEmpty(startDate) ? LocalDate.parse("2022-01-01") : LocalDate.parse(startDate);
        LocalDate end = StringUtils.isEmpty(endDate) ? LocalDate.now() : LocalDate.parse(endDate);
        // 判断时间范围正确性
        DateUtils.judgeDate(start, end);
        List<BsQiyeBusinessData> businessData = businessDataList(start, end);
        return Result.success(consumeTypeInfo(businessData));
    }

    @GetMapping("/kb/consume/top")
    @ApiOperation("客流分析看板-热门旅游商品top3")
    public Result<List<BsKbConsumeTopDto>> kbConsumeTopThree(String startDate, String endDate) {
        LocalDate end = StringUtils.isEmpty(endDate) ? LocalDate.now() : LocalDate.parse(endDate);
        LocalDate start = StringUtils.isEmpty(startDate) ? LocalDate.parse("2022-01-01") : LocalDate.parse(startDate);
        // 判断时间范围正确性
        DateUtils.judgeDate(start, end);
        List<BsQiyeBusinessData> businessData = businessDataList(start, end);

        List<BsKbConsumeTopDto> resultList = new ArrayList<>();
        if (CollUtil.isNotEmpty(businessData)) {
            List<Long> qiyeIds = businessData.stream().map(BsQiyeBusinessData::getQiyeId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            LambdaQueryWrapper<BsQiye> qiyeWrapper = new LambdaQueryWrapper<>();
            qiyeWrapper.select(BsQiye::getId, BsQiye::getName);
            qiyeWrapper.in(BsQiye::getId, qiyeIds);
            // 店铺数量
            List<BsQiye> qiyeList = qiyeMapper.selectList(qiyeWrapper);
            Map<Long, BsQiye> qiyeMap = qiyeList.stream().collect(Collectors.toMap(BsQiye::getId, Function.identity()));
            Map<Long, List<BsQiyeBusinessData>> businessCollect = businessData.stream().collect(Collectors.groupingBy(BsQiyeBusinessData::getQiyeId));
            for (Map.Entry<Long, List<BsQiyeBusinessData>> entry : businessCollect.entrySet()) {
                BsQiye qiye = qiyeMap.get(entry.getKey());
                if (ObjectUtil.isNotNull(qiye)) {
                    BigDecimal total = entry.getValue().stream().map(BsQiyeBusinessData::getBusinessAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                    BsKbConsumeTopDto consumeTop = BsKbConsumeTopDto.builder()
                            .qiyeName(qiye.getName())
                            .price(total)
                            .build();
                    resultList.add(consumeTop);
                }
            }
        }

        if (CollUtil.isNotEmpty(resultList)) {
            resultList = resultList.stream().sorted(Comparator.comparing(BsKbConsumeTopDto::getPrice).reversed())
                    .limit(3)
                    .collect(Collectors.toList());

            List<BigDecimal> priceList = resultList.stream().map(BsKbConsumeTopDto::getPrice).collect(Collectors.toList());
            List<Double> rateList = CollectionUtils.fullRatePercent(priceList, 1);
            for (int i = 0; i < resultList.size(); i++) {
                resultList.get(i).setRate(rateList.get(i));
            }
        }

        return Result.success(resultList);
    }

    @GetMapping("/operate/info")
    @ApiOperation("管理端-经营数据-消费详情")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "date", value = "日期", example = "2023-09-01", required = true),
    })
    public Result<Map<String, Object>> operateInfo(String date) {
        LocalDate localDate = LocalDate.parse(date);
        return Result.success(consumeInfo(localDate, localDate));
    }

    @GetMapping("/operate/sort")
    @ApiOperation("管理端-经营数据-景区消费排名")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "date", value = "日期", example = "2023-09-01", required = true),
    })
    public Result<?> operateSort(String date) {
        LocalDate localDate = LocalDate.parse(date);
        LocalDate compareDate = localDate.minusDays(1);
        // 获取景区消费数据
        List<BsStatisticOperateTopDto> resultList = jinquConsumeInfo(localDate, localDate);
        List<BsStatisticOperateTopDto> compareList = jinquConsumeInfo(compareDate, compareDate);

        if (CollUtil.isNotEmpty(resultList)) {
            // 排序
            resultList = resultList.stream()
                    .sorted(Comparator.comparing(BsStatisticOperateTopDto::getTotalPrice).reversed())
                    .collect(Collectors.toList());
            Map<String, BsStatisticOperateTopDto> compareMap = compareList.stream().collect(Collectors.toMap(BsStatisticOperateTopDto::getJingquName, Function.identity()));
            for (BsStatisticOperateTopDto source : resultList) {
                BsStatisticOperateTopDto comare = compareMap.get(source.getJingquName());
                if (ObjectUtil.isNull(comare) || comare.getTotalPrice().doubleValue() == 0) {
                    source.setRate(BigDecimal.ZERO);
                } else {
                    BigDecimal subtract = source.getTotalPrice().subtract(comare.getTotalPrice());
                    BigDecimal rate = subtract.multiply(new BigDecimal("100")).divide(comare.getTotalPrice(), 2, BigDecimal.ROUND_HALF_UP);
                    source.setRate(rate);
                }
            }
        }
        return Result.success(resultList);
    }

    @GetMapping("/flow/info")
    @ApiOperation("管理端-流量数据-入园人数统计")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "date", value = "日期", example = "2023-09-01", required = true),
    })
    public Result<?> FlowInfo(String date) {
        LocalDate localDate = LocalDate.parse(date);
        return Result.success(flowInfo(localDate, localDate));
    }

    @GetMapping("/flow/sort")
    @ApiOperation("管理端-流量数据-入园年龄比")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "date", value = "日期", example = "2023-09-01", required = true),
    })
    public Result<?> FlowSort(String date) {
        LocalDate localDate = LocalDate.parse(date);
        return Result.success(ageCompare(localDate, localDate));
    }

    @GetMapping("/week/report/operate/total")
    @ApiOperation("管理端-运营周报-经营篇-总营业详情")
    public Result<?> weekReportOperateTotal(Integer year, Integer week) {
        Map<String, LocalDate> dateMap = DateUtils.weekOfYear(year, week);
        LocalDate startDate = dateMap.get("startDate");
        LocalDate endDate = dateMap.get("endDate");

        // 判断时间范围正确性
        DateUtils.judgeDate(startDate, endDate);

        List<BsQiyeBusinessData> businessDataList = businessDataList(startDate, endDate);
        List<BsOrderDetails> orderDetailsList = orderDetailsList(startDate, endDate);

        // 总营收：只统计门票
        BigDecimal totalOrderPrice = orderTotalPrice(orderDetailsList);
        // 企业上报收入
        BigDecimal totalBusinessPrice = businessTotalPrice(businessDataList);
        // 总营业额 = 总营收 + 企业上报收入
        BigDecimal totalPrice = totalOrderPrice.add(totalBusinessPrice);

        LocalDate compareStartDate = startDate.minusDays(7);
        LocalDate compareEndDate = endDate.minusDays(7);
        List<BsOrderDetails> compareOrderDetailsList = orderDetailsList(compareStartDate, compareEndDate);
        List<BsQiyeBusinessData> compareBusinessDataList = businessDataList(compareStartDate, compareEndDate);
        // 总营收：只统计门票
        BigDecimal compareTotalOrderPrice = orderTotalPrice(compareOrderDetailsList);
        // 企业上报收入
        BigDecimal compareTotalBusinessPrice = businessTotalPrice(compareBusinessDataList);
        // 总营业额 = 总营收 + 企业上报收入
        BigDecimal compareTotalPrice = compareTotalOrderPrice.add(compareTotalBusinessPrice);
        
        // 环比 = (本周 - 上周) / 上周
        BigDecimal subtractDecimal = totalPrice.subtract(compareTotalPrice);
        BigDecimal totalQoqDecimal = compareTotalPrice.doubleValue() == 0 ? totalPrice.divide(new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_UP) : subtractDecimal.multiply(new BigDecimal("100")).divide(compareTotalPrice, 2, BigDecimal.ROUND_HALF_UP);

        BigDecimal subtractOrderDecimal = totalOrderPrice.subtract(compareTotalOrderPrice);
        BigDecimal orderQoqDecimal = compareTotalOrderPrice.doubleValue() == 0 ? totalOrderPrice.divide(new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_UP) : subtractOrderDecimal.multiply(new BigDecimal("100")).divide(compareTotalOrderPrice, 2, BigDecimal.ROUND_HALF_UP);

        // -------------------------------   分类统计   ------------------------------------
        Map<String, Object> consumeTypeMap = consumeTypeInfo(businessDataList);

        Map<String, Object> resultMap = new HashMap<>(18);
        // xxxx年x周对应的日期区间
        resultMap.put("date", startDate.toString() + " ~ " + endDate.toString());
        // 总营业额
        resultMap.put("totalPrice", totalPrice);
        // 总营收
        resultMap.put("orderPrice", totalOrderPrice);
        // 总营业额环比
        resultMap.put("totalQoq", totalQoqDecimal.toString());
        // 总营收环比
        resultMap.put("orderQoq", orderQoqDecimal.toString());
        // 分类统计
        resultMap.putAll(consumeTypeMap);
        return Result.success(resultMap);
    }

    @GetMapping("/week/report/operate/flow/compare")
    @ApiOperation("管理端-运营周报-经营篇-人流量与营业额对比图")
    public Result<?> weekReportOperateFlowCompare(Integer year, Integer week) {
        Map<String, LocalDate> dateMap = DateUtils.weekOfYear(year, week);
        LocalDate startDate = dateMap.get("startDate");
        LocalDate endDate = dateMap.get("endDate");

        // 判断时间范围正确性
        DateUtils.judgeDate(startDate, endDate);

        List<BsOrderInfo> orderInfoList = orderInfoList(startDate, endDate);
        List<BsOrderDetails> orderDetailsList = orderDetailsList(orderInfoList);
        List<BsQiyeBusinessData> businessDataList = businessDataList(startDate, endDate);

        List<String> dateList = new ArrayList<>();
        List<Integer> peopleCountList = new ArrayList<>();
        List<BigDecimal> priceList = new ArrayList<>();
        Stream.iterate(startDate,i->i.plusDays(1)).limit(DateUtils.dayLength(startDate, endDate)).forEach(i->{
            List<BsOrderInfo> tempOrderInfoList = orderInfoList.stream().filter(x -> DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, x.getOrderDate()).equalsIgnoreCase(i.toString())).collect(Collectors.toList());
            List<BsOrderDetails> tempOrderDetails = filterOrderDetails(tempOrderInfoList, orderDetailsList);
            List<BsQiyeBusinessData> tempBusinessDataList = businessDataList.stream().filter(x->x.getDate().equals(i.toString())).collect(Collectors.toList());
            // 总营收：只统计门票
            BigDecimal orderPrice = orderTotalPrice(tempOrderDetails);
            // 企业上报收入
            BigDecimal businessPrice = businessTotalPrice(tempBusinessDataList);
            // 总营业额 = 总营收 + 企业上报收入
            BigDecimal price = orderPrice.add(businessPrice);

            int peopleCount = CollUtil.isEmpty(tempOrderDetails) ? 0 : tempOrderDetails.stream().mapToInt(BsOrderDetails::getOrderNum).sum();

            dateList.add(i.toString());
            peopleCountList.add(peopleCount);
            priceList.add(price);
        });

        // 总人流量
        Integer peopleCount = peopleCountList.stream().reduce(0, Integer::sum);
        // 总价格
        BigDecimal totalPrice = priceList.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        // 企业总数
        Long qiyeCount = CollUtil.isNotEmpty(businessDataList) ? businessDataList.stream().map(BsQiyeBusinessData::getQiyeId).distinct().count() : 0;

        Map<String, Object> resultMap = new HashMap<>(6);
        resultMap.put("dateList", dateList);
        resultMap.put("totalPrice", totalPrice);
        resultMap.put("peopleCount", peopleCount);
        resultMap.put("qiyeCount", qiyeCount);
        resultMap.put("priceList", priceList);
        resultMap.put("peopleCountList", peopleCountList);
        return Result.success(resultMap);
    }

    @GetMapping("/week/report/operate/top")
    @ApiOperation("管理端-运营周报-经营篇-景区营业额top5")
    public Result<?> weekReportOperateTopFive(Integer year, Integer week) {
        Map<String, LocalDate> dateMap = DateUtils.weekOfYear(year, week);
        LocalDate startDate = dateMap.get("startDate");
        LocalDate endDate = dateMap.get("endDate");

        // 判断时间范围正确性
        DateUtils.judgeDate(startDate, endDate);

        // 获取景区消费数据
        List<BsStatisticOperateTopDto> resultList = jinquConsumeInfo(startDate, endDate);
        if (CollUtil.isNotEmpty(resultList)) {
            resultList = resultList.stream()
                    .sorted(Comparator.comparing(BsStatisticOperateTopDto::getTotalPrice).reversed())
                    .limit(5).collect(Collectors.toList());
        }
        return Result.success(resultList);
    }

    @GetMapping("/week/report/flow/total")
    @ApiOperation("管理端-运营周报-流量篇-总流量详情")
    public Result<?> weekReportFlowTotal(Integer year, Integer week) {
        Map<String, LocalDate> dateMap = DateUtils.weekOfYear(year, week);
        LocalDate startDate = dateMap.get("startDate");
        LocalDate endDate = dateMap.get("endDate");
        return Result.success(flowInfo(startDate, endDate));
    }

    @GetMapping("/week/report/flow/compare")
    @ApiOperation("管理端-运营周报-流量篇-入园性别时间比")
    public Result<?> weekReportFlowCompare(Integer year, Integer week) {
        Map<String, LocalDate> dateMap = DateUtils.weekOfYear(year, week);
        LocalDate startDate = dateMap.get("startDate");
        LocalDate endDate = dateMap.get("endDate");

        // 判断时间范围正确性
        DateUtils.judgeDate(startDate, endDate);

        return Result.success(sexCompare(startDate, endDate));
    }

    @GetMapping("/week/report/age/compare")
    @ApiOperation("管理端-运营周报-流量篇-入园年龄比")
    public Result<?> weekReportAgeCompare(Integer year, Integer week) {
        Map<String, LocalDate> dateMap = DateUtils.weekOfYear(year, week);
        LocalDate startDate = dateMap.get("startDate");
        LocalDate endDate = dateMap.get("endDate");

        // 判断时间范围正确性
        DateUtils.judgeDate(startDate, endDate);

        return Result.success(ageCompare(startDate, endDate));
    }

    @GetMapping("/week/report/flow/top")
    @ApiOperation("管理端-运营周报-流量篇-入园人数top5")
    public Result<?> weekReportFlowTopFive(Integer year, Integer week) {
        Map<String, LocalDate> dateMap = DateUtils.weekOfYear(year, week);
        LocalDate startDate = dateMap.get("startDate");
        LocalDate endDate = dateMap.get("endDate");

        // 判断时间范围正确性
        DateUtils.judgeDate(startDate, endDate);

        List<BsStatisticFlowTopDto> resultList = jingquFlowInfo(startDate, endDate);

        if (CollUtil.isNotEmpty(resultList)) {
            resultList = resultList.stream()
                    .sorted(Comparator.comparing(BsStatisticFlowTopDto::getUserCount).reversed())
                    .limit(5).collect(Collectors.toList());
        }
        return Result.success(resultList);
    }

    @GetMapping("/week/report/flow/provice")
    @ApiOperation("管理端-运营周报-流量篇-省外客源排名")
    public Result<?> weekReportFlowProvice(Integer year, Integer week) {
        Map<String, LocalDate> dateMap = DateUtils.weekOfYear(year, week);
        LocalDate startDate = dateMap.get("startDate");
        LocalDate endDate = dateMap.get("endDate");
        List<BsOrderDetails> orderDetails = orderDetailsList(startDate, endDate);

        // 判断时间范围正确性
        DateUtils.judgeDate(startDate, endDate);

        List<BsUserContract> userContractList = contractList(orderDetails);
        List<BsStatisticFlowAreaDto> proviceDtoList = new ArrayList<>();
        if (CollUtil.isNotEmpty(orderDetails) && CollUtil.isNotEmpty(userContractList)) {
            Map<Long, BsUserContract> userContractMap = userContractList.stream().collect(Collectors.toMap(BsUserContract::getContractId, Function.identity()));
            for (BsOrderDetails details : orderDetails) {
                String[] contractIdArr = details.getContractId().split(",");
                for (String contractId : contractIdArr) {
                    BsUserContract contract = userContractMap.get(Long.valueOf(contractId));
                    if (ObjectUtil.isNotNull(contract)) {
                        BsStatisticFlowAreaDto proviceDto = BsStatisticFlowAreaDto.builder()
                                .name(IdCardUtils.getProvince(Integer.parseInt(contract.getContractCard().substring(0, 2))))
                                .build();
                        proviceDtoList.add(proviceDto);
                    }
                }
            }
        }

        return Result.success(areaGroupAndSort(proviceDtoList));
    }

    @GetMapping("/week/report/flow/market")
    @ApiOperation("管理端-运营周报-流量篇-省内客源排名")
    public Result<?> weekReportFlowMarket(Integer year, Integer week) {
        Map<String, LocalDate> dateMap = DateUtils.weekOfYear(year, week);
        LocalDate startDate = dateMap.get("startDate");
        LocalDate endDate = dateMap.get("endDate");

        // 判断时间范围正确性
        DateUtils.judgeDate(startDate, endDate);

        List<BsOrderDetails> orderDetails = orderDetailsList(startDate, endDate);
        List<BsUserContract> userContractList = contractList(orderDetails);
        List<BsStatisticFlowAreaDto> marketList = new ArrayList<>();
        if (CollUtil.isNotEmpty(orderDetails) && CollUtil.isNotEmpty(userContractList)) {
            Map<Long, BsUserContract> userContractMap = userContractList.stream().collect(Collectors.toMap(BsUserContract::getContractId, Function.identity()));
            for (BsOrderDetails details : orderDetails) {
                String[] contractIdArr = details.getContractId().split(",");
                for (String contractId : contractIdArr) {
                    BsUserContract contract = userContractMap.get(Long.valueOf(contractId));
                    if (ObjectUtil.isNotNull(contract)) {
                        String province = IdCardUtils.getProvince(Integer.parseInt(contract.getContractCard().substring(0, 2)));
                        if (province.equalsIgnoreCase("安徽省")) {
                            BsStatisticFlowAreaDto market = BsStatisticFlowAreaDto.builder()
                                    .name(IdCardUtils.getMarket(Integer.parseInt(contract.getContractCard().substring(0, 4))))
                                    .build();
                            marketList.add(market);
                        }
                    }
                }
            }
        }

        return Result.success(areaGroupAndSort(marketList));
    }

    public Map<String, Object> consumeInfo(LocalDate startDate, LocalDate endDate) {
        Map<String, Object> resultMap = new HashMap<>(3);
        LambdaQueryWrapper<BsQiye> qiyeWrapper = new LambdaQueryWrapper<>();
        qiyeWrapper.select(BsQiye::getId);
        // 审核通过
        qiyeWrapper.ne(BsQiye::getAuditStatus, "1");
        // 未撤场
        qiyeWrapper.ne(BsQiye::getStatus, Constants.UN_LEAVE_STATUS);
        // 店铺数量
        Integer qiyeCount = qiyeMapper.selectCount(qiyeWrapper);

        BigDecimal totalPrice = new BigDecimal("0");
        BigDecimal avgPrice = new BigDecimal("0");

        List<BsOrderDetails> orderDetails = orderDetailsList(startDate, endDate);
        List<BsQiyeBusinessData> businessDataList = businessDataList(startDate, endDate);
        if (CollUtil.isNotEmpty(orderDetails)) {
            totalPrice = orderTotalPrice(orderDetails);
            BigDecimal businessTotalPrice = businessTotalPrice(businessDataList);
            totalPrice = totalPrice.add(businessTotalPrice);
            int totalOrderNum = orderDetails.stream().mapToInt(BsOrderDetails::getOrderNum).sum();
            avgPrice = totalPrice.divide(new BigDecimal(totalOrderNum + ""), 2, BigDecimal.ROUND_HALF_UP);
        }

        resultMap.put("shopCount", qiyeCount);
        resultMap.put("totalPrice", totalPrice);
        resultMap.put("avgPrice", avgPrice);
        return resultMap;
    }

    /**
     * 根据时间周期获取景区消费详情信息
     * @param startDate: 开始时间
     * @param endDate: 结束时间
     * @return: java.util.List<com.ruoyi.system.domain.dto.BsStatisticOperateTopDto>
     * @author: kenn
     * @date: 2023/12/8 10:27
     */
    public List<BsStatisticOperateTopDto> jinquConsumeInfo(LocalDate startDate, LocalDate endDate) {
        // 判断时间范围正确性
        DateUtils.judgeDate(startDate, endDate);

        LambdaQueryWrapper<BsJingqu> jingquWrapper = new LambdaQueryWrapper<>();
        jingquWrapper.eq(BsJingqu::getDelFlag, Constants.LOGIC_NOT_DELETE);
        List<BsJingqu> jingquList = jingquService.list(jingquWrapper);

        LambdaQueryWrapper<BsQiye> qiyeWrapper = new LambdaQueryWrapper<>();
        qiyeWrapper.select(BsQiye::getId, BsQiye::getJingquId);
        // 审核通过
        qiyeWrapper.ne(BsQiye::getAuditStatus, "1");
        // 未撤场
        qiyeWrapper.ne(BsQiye::getStatus, Constants.UN_LEAVE_STATUS);
        List<BsQiye> qiyeList = qiyeMapper.selectList(qiyeWrapper);

        List<BsOrderInfo> orderInfoList = orderInfoList(startDate, endDate);
        List<BsOrderDetails> orderDetailsList = orderDetailsList(orderInfoList);
        List<BsQiyeBusinessData> businessDataList = businessDataList(startDate, endDate);

        List<BsStatisticOperateTopDto> resultList = new ArrayList<>();
        for (BsJingqu jingqu : jingquList) {
            List<Long> tempQiyeIds = qiyeList.stream().filter(i -> jingqu.getJingquId().equals(i.getJingquId())).map(BsQiye::getId).collect(Collectors.toList());
            List<BsQiyeBusinessData> tempBusinessDatas = businessDataList.stream().filter(i -> tempQiyeIds.contains(i.getQiyeId())).collect(Collectors.toList());
            List<BsOrderInfo> tempOrderInfos = orderInfoList.stream().filter(i -> jingqu.getJingquId().equals(i.getJingquId())).collect(Collectors.toList());
            List<BsOrderDetails> tempOrderDetails = filterOrderDetails(tempOrderInfos, orderDetailsList);
            BigDecimal orderPrice = orderTotalPrice(tempOrderDetails);
            BigDecimal businessPrice = businessTotalPrice(tempBusinessDatas);
            BigDecimal totalPrice = orderPrice.add(businessPrice);
            BigDecimal avgPrice = tempQiyeIds.size() == 0 ? totalPrice : totalPrice.divide(new BigDecimal(tempQiyeIds.size() + ""), 2, BigDecimal.ROUND_HALF_UP);
            BigDecimal dayAvgPrice = totalPrice.divide(new BigDecimal("7"), 2, BigDecimal.ROUND_HALF_UP);
            BsStatisticOperateTopDto result = BsStatisticOperateTopDto.builder()
                    .jingquName(jingqu.getJingquName())
                    .totalPrice(totalPrice)
                    .avgPrice(avgPrice)
                    .dayAvgPrice(dayAvgPrice)
                    .qiyeCount(tempQiyeIds.size())
                    .build();
            resultList.add(result);
        }
        return resultList;
    }

    /**
     * 根据时间周期获取总人流量详情
     * @param startDate: 开始时间
     * @param endDate: 结束时间
     * @return: java.util.Map<java.lang.String, java.lang.Object>
     * @author: kenn
     * @date: 2023/12/8 10:52
     */
    public Map<String, Object> flowInfo(LocalDate startDate, LocalDate endDate) {
        List<BsOrderDetails> orderDetails = orderDetailsList(startDate, endDate);
        Integer total = 0;
        Integer male = 0;
        Integer female = 0;
        List<BsUserContract> userContractList = contractList(orderDetails);
        if (CollUtil.isNotEmpty(orderDetails) && CollUtil.isNotEmpty(userContractList)) {
            Map<Long, BsUserContract> userContractMap = userContractList.stream().collect(Collectors.toMap(BsUserContract::getContractId, Function.identity()));
            for (BsOrderDetails details : orderDetails) {
                String[] contractIdArr = details.getContractId().split(",");
                for (String contractId : contractIdArr) {
                    total++;
                    BsUserContract contract = userContractMap.get(Long.valueOf(contractId));
                    if (ObjectUtil.isNotNull(contract) && IdCardUtils.getSex(contract.getContractCard()) == 1) {
                        male++;
                    } else {
                        female++;
                    }
                }
            }
        }

        Map<String, Object> resultMap = new HashMap<>(3);
        resultMap.put("total", total);
        resultMap.put("male", male);
        resultMap.put("female", female);
        return resultMap;
    }

    /**
     * 根据时间周期获取景区人流量信息
     * @param startDate: 开始时间
     * @param endDate: 结束时间
     * @return: java.util.List<com.ruoyi.system.domain.dto.BsStatisticFlowTopDto>
     * @author: kenn
     * @date: 2023/12/8 10:48
     */
    public List<BsStatisticFlowTopDto> jingquFlowInfo(LocalDate startDate, LocalDate endDate) {
        LambdaQueryWrapper<BsJingqu> jingquWrapper = new LambdaQueryWrapper<>();
        jingquWrapper.eq(BsJingqu::getDelFlag, Constants.LOGIC_NOT_DELETE);
        List<BsJingqu> jingquList = jingquService.list(jingquWrapper);

        List<BsOrderInfo> orderInfoList = orderInfoList(startDate, endDate);
        List<BsOrderDetails> orderDetailsList = orderDetailsList(orderInfoList);

        List<BsStatisticFlowTopDto> resultList = new ArrayList<>();
        for (BsJingqu jingqu : jingquList) {
            List<BsOrderInfo> tempOrderInfos = orderInfoList.stream().filter(i -> jingqu.getJingquId().equals(i.getJingquId())).collect(Collectors.toList());
            List<BsOrderDetails> tempOrderDetails = filterOrderDetails(tempOrderInfos, orderDetailsList);
            int total = 0;
            if (CollUtil.isNotEmpty(tempOrderDetails)) {
                for (BsOrderDetails details : tempOrderDetails) {
                    String[] contractIdArr = details.getContractId().split(",");
                    total += contractIdArr.length;
                }
            }

            Integer dayAvgCount = total == 0 ? 0 : new BigDecimal(Integer.toString(total)).divide(new BigDecimal("7"), 0, BigDecimal.ROUND_HALF_UP).intValue();
            BsStatisticFlowTopDto result = BsStatisticFlowTopDto.builder()
                    .jingquName(jingqu.getJingquName())
                    .userCount(total)
                    .dayAvgCount(dayAvgCount)
                    .build();
            resultList.add(result);
        }
        return resultList;
    }

    /**
     * 根据时间范围统计入园性别时间比
     * @param startDate: 开始时间
     * @param endDate: 结束时间
     * @return: java.util.Map<java.lang.String, java.lang.Object>
     * @author: kenn
     * @date: 2023/12/8 10:03
     */
    public Map<String, Object> sexCompare(LocalDate startDate, LocalDate endDate) {
        // 判断时间范围正确性
        DateUtils.judgeDate(startDate, endDate);

        List<BsOrderInfo> orderInfoList = orderInfoList(startDate, endDate);
        List<BsOrderDetails> orderDetailsList = orderDetailsList(orderInfoList);
        List<BsUserContract> contractList = contractList(orderDetailsList);
        Map<Long, BsUserContract> userContractMap = contractList.stream().collect(Collectors.toMap(BsUserContract::getContractId, Function.identity()));;

        List<String> dateList = new ArrayList<>();
        List<Integer> maleList = new ArrayList<>();
        List<Integer> femaleList = new ArrayList<>();
        Stream.iterate(startDate,i->i.plusDays(1)).limit(DateUtils.dayLength(startDate, endDate)).forEach(i->{
            List<BsOrderInfo> tempOrderInfoList = orderInfoList.stream().filter(x -> DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, x.getOrderDate()).equalsIgnoreCase(i.toString())).collect(Collectors.toList());
            List<BsOrderDetails> tempOrderDetails = filterOrderDetails(tempOrderInfoList, orderDetailsList);
            Integer male = 0;
            Integer female = 0;
            if (CollUtil.isNotEmpty(tempOrderDetails) && CollUtil.isNotEmpty(userContractMap)) {
                for (BsOrderDetails details : tempOrderDetails) {
                    String[] contractIdArr = details.getContractId().split(",");
                    for (String contractId : contractIdArr) {
                        BsUserContract contract = userContractMap.get(Long.valueOf(contractId));
                        if (ObjectUtil.isNotNull(contract) && IdCardUtils.getSex(contract.getContractCard()) == 1) {
                            male++;
                        } else {
                            female++;
                        }
                    }
                }
            }
            dateList.add(i.toString());
            maleList.add(male);
            femaleList.add(female);
        });

        Map<String, Object> resultMap = new HashMap<>(3);
        resultMap.put("dateList", dateList);
        resultMap.put("maleList", maleList);
        resultMap.put("femaleList", femaleList);
        return resultMap;
    }

    /**
     * 根据时间范围统计入园年龄比
     * @param startDate: 开始时间
     * @param endDate: 结束时间
     * @return: java.util.Map<java.lang.String, java.lang.Object>
     * @author: kenn
     * @date: 2023/12/8 10:01
     */
    public Map<String, Object> ageCompare(LocalDate startDate, LocalDate endDate) {
        // 判断时间范围正确性
        DateUtils.judgeDate(startDate, endDate);

        List<BsOrderDetails> orderDetails = orderDetailsList(startDate, endDate);
        Integer eighteenUnder = 0;
        Integer twentyFive = 0;
        Integer fortyFive = 0;
        Integer sixty = 0;
        Integer sixtAbove = 0;
        List<BsUserContract> userContractList = contractList(orderDetails);
        if (CollUtil.isNotEmpty(orderDetails) && CollUtil.isNotEmpty(userContractList)) {
            Map<Long, BsUserContract> userContractMap = userContractList.stream().collect(Collectors.toMap(BsUserContract::getContractId, Function.identity()));
            for (BsOrderDetails details : orderDetails) {
                String[] contractIdArr = details.getContractId().split(",");
                for (String contractId : contractIdArr) {
                    BsUserContract contract = userContractMap.get(Long.valueOf(contractId));
                    if (ObjectUtil.isNotNull(contract)) {
                        int age = IdCardUtils.getAge(contract.getContractCard());
                        if (age < 18) {
                            eighteenUnder++;
                        } else if (age < 25) {
                            twentyFive++;
                        } else if (age < 45) {
                            fortyFive++;
                        } else if (age < 60) {
                            sixty++;
                        } else {
                            sixtAbove++;
                        }
                    }
                }
            }
        }

        List<String> typeList = Arrays.asList("18岁以下", "18岁~25岁", "25岁~45岁", "45岁~60岁", "60岁以上");
        List<Integer> typeCountList = Arrays.asList(eighteenUnder, twentyFive, fortyFive, sixty, sixtAbove);
        List<Double> rateList = CollectionUtils.fullRatePercent(typeCountList.stream().map(BigDecimal::valueOf).collect(Collectors.toList()), 2);

        Map<String, Object> resultMap = new HashMap<>(3);
        resultMap.put("type", typeList);
        resultMap.put("count", typeCountList);
        resultMap.put("rate", rateList);
        return resultMap;
    }

    public Map<String, Object> consumeTypeInfo(List<BsQiyeBusinessData> businessDataList) {
        // 游玩消费
        Integer youwanCount = 0;
        BigDecimal youwanPrice = new BigDecimal("0");
        // 餐饮消费
        Integer canyinCount = 0;
        BigDecimal canyinPrice = new BigDecimal("0");
        // 住宿消费
        Integer zhusuCount = 0;
        BigDecimal zhusuPrice = new BigDecimal("0");
        // 其他消费
        Integer qitaCount = 0;
        BigDecimal qitaPrice = new BigDecimal("0");
        if (CollUtil.isNotEmpty(businessDataList)) {
            List<Long> qiyeIds = businessDataList.stream().map(BsQiyeBusinessData::getQiyeId).collect(Collectors.toList());
            LambdaQueryWrapper<BsQiye> qiyeWrapper = new LambdaQueryWrapper<>();
            qiyeWrapper.in(BsQiye::getId, qiyeIds);
            qiyeWrapper.select(BsQiye::getId, BsQiye::getType);
            List<BsQiye> qiyeList = qiyeMapper.selectList(qiyeWrapper);
            Map<String, List<BsQiye>> typeMap = qiyeList.stream().collect(Collectors.groupingBy(BsQiye::getType));
            for (Map.Entry<String, List<BsQiye>> entry : typeMap.entrySet()) {
                List<Long> tempQiyeIds = entry.getValue().stream().map(BsQiye::getId).collect(Collectors.toList());
                List<BsQiyeBusinessData> tempBusinessData = businessDataList.stream().filter(i -> tempQiyeIds.contains(i.getQiyeId())).collect(Collectors.toList());
                BigDecimal tempBusinessTotal = businessTotalPrice(tempBusinessData);
                switch (entry.getKey()) {
                    case "canyin":
                        canyinPrice = canyinPrice.add(tempBusinessTotal);
                        canyinCount++;
                        break;
                    case "jiudian":
                    case "minsu":
                        zhusuPrice = zhusuPrice.add(tempBusinessTotal);
                        zhusuCount++;
                        break;
                    case "wenwan":
                    case "baihuo":
                        youwanPrice = youwanPrice.add(tempBusinessTotal);
                        youwanCount++;
                        break;
                    default:
                        qitaPrice = qitaPrice.add(tempBusinessTotal);
                        qitaCount++;
                }
            }
        }

        List<Double> rateList = CollectionUtils.fullRatePercent(Arrays.asList(youwanPrice, canyinPrice, zhusuPrice, qitaPrice), 2);

        Map<String, Object> resultMap = new HashMap<>(12);
        // 游玩类
        resultMap.put("youwanPrice", youwanPrice.toString());
        resultMap.put("youwanCount", youwanCount);
        resultMap.put("youwanRate", rateList.get(0));
        // 餐饮类
        resultMap.put("canyinPrice", canyinPrice.toString());
        resultMap.put("canyinCount", canyinCount);
        resultMap.put("canyinRate", rateList.get(1));
        // 住宿类
        resultMap.put("zhusuPrice", zhusuPrice.toString());
        resultMap.put("zhusuCount", zhusuCount);
        resultMap.put("zhusuRate", rateList.get(2));
        // 其他
        resultMap.put("qitaPrice", qitaPrice.toString());
        resultMap.put("qitaCount", qitaCount);
        resultMap.put("qitaRate", rateList.get(3));
        return resultMap;
    }

    /**
     * 获取所传订单详情的总金额
     * @param orderDetailsList: 订单详情
     * @return: java.math.BigDecimal
     * @author: kenn
     * @date: 2023/12/8 10:17
     */
    private BigDecimal orderTotalPrice(List<BsOrderDetails> orderDetailsList) {
        BigDecimal totalOrderPrice = new BigDecimal("0");
        if (CollUtil.isNotEmpty(orderDetailsList)) {
            totalOrderPrice = orderDetailsList.stream().map(BsOrderDetails::getOrderPrice).filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
        }
        return totalOrderPrice;
    }

    /**
     * 获取所传企业经营数据的总金额
     * @param businessDataList:	企业经营数据
     * @return: java.math.BigDecimal
     * @author: kenn
     * @date: 2023/12/8 10:19
     */
    private BigDecimal businessTotalPrice(List<BsQiyeBusinessData> businessDataList) {
        BigDecimal totalBusinessPrice = new BigDecimal("0");
        if (CollUtil.isNotEmpty(businessDataList)) {
            totalBusinessPrice = businessDataList.stream().map(BsQiyeBusinessData::getBusinessAmount).filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
        }
        return totalBusinessPrice;
    }

    /**
     * 根据时间周期获取订单信息
     * @param startDate: 开始时间
     * @param endDate: 结束时间
     * @return: java.util.List<com.ruoyi.system.domain.BsOrderInfo>
     * @author: kenn
     * @date: 2023/12/8 10:21
     */
    private List<BsOrderInfo> orderInfoList(LocalDate startDate, LocalDate endDate) {
        LambdaQueryWrapper<BsOrderInfo> orderInfoWrapper = new LambdaQueryWrapper<>();
        orderInfoWrapper.select(BsOrderInfo::getOrderId, BsOrderInfo::getOrderDate, BsOrderInfo::getJingquId);
        // 已支付订单
        orderInfoWrapper.eq(BsOrderInfo::getOrderPayStatus, 1);
        orderInfoWrapper.between(startDate != null && endDate != null, BsOrderInfo::getOrderDate, startDate.toString(), endDate.toString());
        return orderInfoService.list(orderInfoWrapper);
    }

    /**
     * 根据时间周期获取订单详情数据
     * @param startDate: 开始时间
     * @param endDate: 结束时间
     * @return: java.util.List<com.ruoyi.system.domain.BsOrderDetails>
     * @author: kenn
     * @date: 2023/12/8 10:23
     */
    private List<BsOrderDetails> orderDetailsList(LocalDate startDate, LocalDate endDate) {
        List<BsOrderInfo> orderInfoList = orderInfoList(startDate, endDate);
        return orderDetailsList(orderInfoList);
    }

    /**
     * 根据时间周期获取企业经营数据
     * @param startDate: 开始时间
     * @param endDate: 结束时间
     * @return: java.util.List<com.ruoyi.system.domain.BsQiyeBusinessData>
     * @author: kenn
     * @date: 2023/12/8 10:21
     */
    private List<BsQiyeBusinessData> businessDataList(LocalDate startDate, LocalDate endDate) {
        LambdaQueryWrapper<BsQiyeBusinessData> qiyeBusinessDataWrapper = new LambdaQueryWrapper<>();
        // type=1：已上报数据
        qiyeBusinessDataWrapper.eq(BsQiyeBusinessData::getType, "1");
        List<BsQiyeBusinessData> qiyeBusinessDataList = qiyeBusinessDataMapper.selectList(qiyeBusinessDataWrapper);
        if (CollUtil.isNotEmpty(qiyeBusinessDataList)) {
            qiyeBusinessDataList = qiyeBusinessDataList.stream()
                    .filter(i -> {
                        boolean flag = false;
                        LocalDate reportDate = LocalDate.parse(i.getDate());
                        if (reportDate.isEqual(startDate) || reportDate.isEqual(endDate) || (reportDate.isAfter(startDate) && reportDate.isBefore(endDate))) {
                            flag = true;
                        }
                        return flag;
                    }).collect(Collectors.toList());
        }
        return qiyeBusinessDataList;
    }

    /**
     * 根据订单信息获取对应的订单详情数据
     * @param orderInfoList: 订单信息
     * @return: java.util.List<com.ruoyi.system.domain.BsOrderDetails>
     * @author: kenn
     * @date: 2023/12/8 10:24
     */
    private List<BsOrderDetails> orderDetailsList(List<BsOrderInfo> orderInfoList) {
        List<BsOrderDetails> orderDetailsList = null;
        if (CollUtil.isNotEmpty(orderInfoList)) {
            List<Long> orderIds = orderInfoList.stream().map(BsOrderInfo::getOrderId).collect(Collectors.toList());
            LambdaQueryWrapper<BsOrderDetails> orderDetailsWrapper = new LambdaQueryWrapper<>();
            orderDetailsWrapper.select(BsOrderDetails::getOrderPrice, BsOrderDetails::getOrderNum, BsOrderDetails::getOrderId, BsOrderDetails::getContractId);
            orderDetailsWrapper.in(BsOrderDetails::getOrderId, orderIds);
            orderDetailsList = orderDetailsService.list(orderDetailsWrapper);
        }
        return orderDetailsList;
    }

    /**
     * 根据订单信息过滤获取对应订单详情数据
     * @param orderInfoList: 订单信息
     * @param detailsList: 需要过滤的订单详情数据
     * @return: java.util.List<com.ruoyi.system.domain.BsOrderDetails>
     * @author: kenn
     * @date: 2023/12/8 10:24
     */
    private List<BsOrderDetails> filterOrderDetails(List<BsOrderInfo> orderInfoList, List<BsOrderDetails> detailsList) {
        List<BsOrderDetails> orderDetailsList = null;
        if (CollUtil.isNotEmpty(orderInfoList) && CollUtil.isNotEmpty(detailsList)) {
            List<Long> orderIds = orderInfoList.stream().map(BsOrderInfo::getOrderId).collect(Collectors.toList());
            orderDetailsList = detailsList.stream().filter(i->orderIds.contains(i.getOrderId())).collect(Collectors.toList());
        }
        return orderDetailsList;
    }

    /**
     * 根据订单详情获取对应的订单联系人
     * @param orderDetails:	订单详情
     * @return: java.util.List<com.ruoyi.system.domain.BsUserContract>
     * @author: kenn
     * @date: 2023/12/8 10:29
     */
    private List<BsUserContract> contractList(List<BsOrderDetails> orderDetails) {
        List<BsUserContract> userContractList = new ArrayList<>();
        if (CollUtil.isNotEmpty(orderDetails)) {
            Set<Long> contractIdSet = new HashSet<>();
            List<String> contractIdStrs = orderDetails.stream().map(BsOrderDetails::getContractId).collect(Collectors.toList());
            for (String contractIdStr : contractIdStrs) {
                String[] contractIdArr = contractIdStr.split(",");
                for (String contractId : contractIdArr) {
                    contractIdSet.add(Long.valueOf(contractId));
                }
            }
            LambdaQueryWrapper<BsUserContract> contractWrapper = new LambdaQueryWrapper<>();
            contractWrapper.in(BsUserContract::getContractId, contractIdSet);
            contractWrapper.select(BsUserContract::getContractId, BsUserContract::getContractCard);
            userContractList = contractService.list(contractWrapper);
        }
        return userContractList;
    }

    /**
     * 根据订单详情过滤获取对应的订单联系人
     * @param orderDetails:	订单详情
     * @param userContractList:	需要过滤的订单联系人数据
     * @return: java.util.List<com.ruoyi.system.domain.BsUserContract>
     * @author: kenn
     * @date: 2023/12/8 10:29
     */
    private List<BsUserContract> filterContractList(List<BsOrderDetails> orderDetails, List<BsUserContract> userContractList) {
        List<BsUserContract> resultList = null;
        if (CollUtil.isNotEmpty(orderDetails) && CollUtil.isNotEmpty(userContractList)) {
            List<String> contractIdStrs = orderDetails.stream().map(BsOrderDetails::getContractId).collect(Collectors.toList());
            Set<Long> contractIdSet = new HashSet<>();
            for (String contractIdStr : contractIdStrs) {
                String[] contractIdArr = contractIdStr.split(",");
                for (String contractId : contractIdArr) {
                    contractIdSet.add(Long.valueOf(contractId));
                }
            }
            resultList = userContractList.stream().filter(i->contractIdSet.contains(i.getContractId())).collect(Collectors.toList());
        }
        return resultList;
    }

    /**
     * 对省内/外客源分组统计并排序
     * @param areaList:	客源所属区域信息
     * @return: java.util.List<com.ruoyi.system.domain.dto.BsStatisticFlowAreaDto>
     * @author: kenn
     * @date: 2023/12/8 10:42
     */
    private List<BsStatisticFlowAreaDto> areaGroupAndSort(List<BsStatisticFlowAreaDto> areaList) {
        List<BsStatisticFlowAreaDto> resultList = new ArrayList<>();
        if (CollUtil.isNotEmpty(areaList)) {
            Map<String, List<BsStatisticFlowAreaDto>> marketCollect = areaList.stream().collect(Collectors.groupingBy(BsStatisticFlowAreaDto::getName));
            for (Map.Entry<String, List<BsStatisticFlowAreaDto>> entry : marketCollect.entrySet()) {
                BsStatisticFlowAreaDto result = BsStatisticFlowAreaDto.builder()
                        .name(entry.getKey())
                        .count(entry.getValue().size())
                        .build();
                resultList.add(result);
            }
            resultList = resultList.stream()
                    .sorted(Comparator.comparing(BsStatisticFlowAreaDto::getCount).reversed())
                    .collect(Collectors.toList());
        }
        return resultList;
    }

}
